本篇是實作常用的 AWS DynamoDB 服務之 Terraform 模組,並且會使用到 YAML 資料結構來定義模組的內容,完整的專案程式碼分享在我的 Github 上。
./configs/dynamodb/configurations.yaml
與模組 my_dynamodb
的放置位置 modules/my_dynamodb
:├── configs
│ ├── cloudfront
│ │ └── distributions.yaml
│ ├── cloudwatch
│ │ └── loggroups.yaml
│ ├── dynamodb
│ │ └── configurations.yaml
│ ├── iam
│ │ ├── assume_role_policies
│ │ │ ├── eks-cluster.json
│ │ │ ├── eks-fargate-pod-execution-role.json
│ │ │ └── eks-node-group.json
│ │ ├── iam.yaml
│ │ ├── role_policies
│ │ │ └── eks-cluster-cloudwatch-metrics.json
│ │ └── user_policies
│ │ └── admin_access.json
│ ├── kinesis
│ │ └── streams.yaml
│ ├── kms
│ │ ├── keys.yaml
│ │ └── policies
│ │ └── my-key-policy.json
│ ├── s3
│ │ ├── policies
│ │ │ └── my-bucket.json
│ │ └── s3.yaml
│ ├── subnet
│ │ └── my-subnets.yaml
│ └── vpc
│ └── my-vpcs.yaml
├── example.tfvars
├── locals.tf
├── main.tf
├── modules
│ ├── my_aws_load_balancer_controller
│ ├── my_cloudfront
│ ├── my_cloudwatch
│ ├── my_dynamodb
│ │ ├── dynamodb.tf
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ └── variables.tf
│ ├── my_eips
│ ├── my_eks
│ ├── my_eventbridge
│ ├── my_iam
│ ├── my_igw
│ ├── my_instances
│ ├── my_karpenter
│ ├── my_kinesis_stream
│ ├── my_kms
│ ├── my_msk
│ ├── my_nacls
│ ├── my_route_tables
│ ├── my_s3
│ ├── my_subnets
│ └── my_vpc
├── my-ingress-controller-values.yaml
├── my-ingress-node-red.yaml
├── packer
│ └── apache-cassandra
└── variables.tf
./configs/dynamodb/configurations.yaml
內容來定義 DynamoDB 需要用建立的資源:tables:
- name: "TABLE_NAME"
attributes:
- name: "<ATTRIBUTE_NAME>"
type: "<ATTRIBUTE_TYPE>"
billing_mode: "PROVISIONED"
hash_key: "<HASH_KEY>"
range_key: "<RANGE_KEY>"
read_capacity: <READ_CAPACITY>
stream_enabled: <true or false>
table_class: "<TABLE_CLASS>"
write_capacity: <WRITE_CAPACITY>
my_dynamodb
模組:./modules/my_dynamodb/outputs.tf
:output "subnets" {
value = aws_dynamodb_table.tables
}
./modules/my_dynamodb/provider.tf
:provider "aws" {
region = var.aws_region
profile = var.aws_profile
}
./modules/my_dynamodb/variables.tf
:variable "aws_region" {
description = "AWS region"
default = "ap-northeast-1"
}
variable "aws_profile" {
description = "AWS profile"
default = ""
}
variable "project_name" {
type = string
description = "Project name"
default = ""
}
variable "department_name" {
type = string
description = "Department name"
default = "SRE"
}
variable "config_path" {
type = string
description = "table path"
default = ""
}
./modules/my_dynamodb/dynamodb.tf
:locals {
tables = yamldecode(file("${var.config_path}"))["tables"]
}
resource "aws_dynamodb_table" "tables" {
# checkov:skip=CKV_AWS_28: "Ensure Dynamodb point in time recovery (backup) is enabled"
# checkov:skip=CKV_AWS_119: "Ensure DynamoDB Tables are encrypted using a KMS Customer Managed CMK"
# checkov:skip=CKV2_AWS_16: "Ensure that Auto Scaling is enabled on your DynamoDB tables"
for_each = { for r in local.tables : r.name => r }
dynamic "attribute" {
for_each = each.value.attributes
content {
name = attribute.value.name
type = attribute.value.type
}
}
billing_mode = each.value.billing_mode
hash_key = each.value.hash_key
name = each.value.name
point_in_time_recovery {
enabled = "false"
}
range_key = lookup(each.value, "range_key", null)
read_capacity = each.value.read_capacity
stream_enabled = each.value.stream_enabled ? "true" : "false"
table_class = lookup(each.value, "table_class", "STANDARD") == "STANDARD" ? null : each.value.table_class
write_capacity = each.value.write_capacity
}
example.tfvars
:aws_region="ap-northeast-1"
aws_profile="<YOUR_PROFILE>"
project_name="example"
department_name="SRE"
cassandra_root_password="<CASSANDRA_ROOT_PASSWORD>"
main.tf
:terraform {
required_providers {
aws = {
version = "5.15.0"
}
}
backend "s3" {
bucket = "<YOUR_S3_BUCKET_NAME>"
dynamodb_table = "<YOUR_DYNAMODB_TABLE_NAME>"
key = "terraform.tfstate"
region = "ap-northeast-1"
shared_credentials_file = "~/.aws/config"
profile = "<YOUR_PROFILE>"
}
}
其他模組省略...
# dynamodb
module "dynamodb" {
source = "./modules/my_dynamodb"
aws_profile = var.aws_profile
aws_region = var.aws_region
config_path = "./configs/dynamodb/configurations.yaml"
}
tables:
- name: my-table
attributes:
- name: Key
type: S
- name: Path
type: S
billing_mode: "PROVISIONED"
hash_key: Path
range_key: Key
read_capacity: 5
stream_enabled: false
table_class: STANDARD
write_capacity: 5
terraform init && terraform plan --out .plan -var-file=example.tfvars
來確認一下結果:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
+ create
Terraform will perform the following actions:
# module.dynamodb.aws_dynamodb_table.tables["my-table"] will be created
+ resource "aws_dynamodb_table" "tables" {
+ arn = (known after apply)
+ billing_mode = "PROVISIONED"
+ hash_key = "Path"
+ id = (known after apply)
+ name = "my-table"
+ range_key = "Key"
+ read_capacity = 5
+ stream_arn = (known after apply)
+ stream_enabled = false
+ stream_label = (known after apply)
+ stream_view_type = (known after apply)
+ tags_all = (known after apply)
+ write_capacity = 5
+ attribute {
+ name = "Key"
+ type = "S"
}
+ attribute {
+ name = "Path"
+ type = "S"
}
+ point_in_time_recovery {
+ enabled = false
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: .plan
To perform exactly these actions, run the following command to apply:
terraform apply ".plan"
下一篇文章將會展示實作 AWS ECR 之 Terraform 模組。